package room

import (
	"errors"
	"server/common"

	"github.com/mitchellh/mapstructure"
	"github.com/sirupsen/logrus"
)

// -------------------------------------------------------------------------------------------------
//
// -------------------------------------------------------------------------------------------------
func (s *RoomService) checkJoinRoomReqData(data common.SFUJoinRoomReqData) error {
	// Check if room ID is provided
	if data.RoomId == "" {
		return errors.New("room ID is required in join room request")
	}

	// Check if user ID is provided
	if data.UserId == "" {
		return errors.New("user ID is required in join room request")
	}

	// Check if RTP capabilities are provided
	if data.RtpCaps == nil {
		return errors.New("RTP capabilities are required in join room request")
	}

	// Check if room exists
	if !s.roomMgr.RoomExists(data.RoomId) {
		return errors.New("room does not exist")
	}

	return nil
}

// -------------------------------------------------------------------------------------------------
//
// -------------------------------------------------------------------------------------------------
func (s *RoomService) sendJoinRoomSuccessResponse(rid string, connId string, roomId string,
	userId string, userList []string) {
	resMsg := common.Message{
		Cmd: common.SFU_JOIN_ROOM_RES,
		Rid: rid,
		Data: common.ResMsgData{
			Code: 0,
			Msg:  "success",
			Data: common.SFUJoinRoomResData{
				RoomId: roomId,
				UserId: userId,
				Users:  userList,
			},
		},
	}
	s.dispatcher.Dispatch(resMsg, s.serviceInfo, common.AccessServiceInfo, connId)
}

// -------------------------------------------------------------------------------------------------
//
// -------------------------------------------------------------------------------------------------
func (s *RoomService) sendJoinRoomErrorResponse(rid string, code int, msg string,
	connId string, roomId string, userId string) {
	resMsg := common.Message{
		Cmd: common.SFU_JOIN_ROOM_RES,
		Rid: rid,
		Data: common.ResMsgData{
			Code: code,
			Msg:  msg,
			Data: common.SFUJoinRoomResData{
				RoomId: roomId,
				UserId: userId,
			},
		},
	}
	s.dispatcher.Dispatch(resMsg, s.serviceInfo, common.AccessServiceInfo, connId)
}

// -------------------------------------------------------------------------------------------------
//
// -------------------------------------------------------------------------------------------------
func (s *RoomService) handleJoinRoomReq(msg common.Message, from common.ServiceInfo,
	connId string) error {
	LOG().WithFields(logrus.Fields{
		"msg":  common.ToJson(msg),
		"from": from,
	}).Info("Handling Join Room Request")

	var reqData common.SFUJoinRoomReqData
	if err := mapstructure.Decode(msg.Data, &reqData); err != nil {
		LOG(msg.Rid).WithError(err).Error("Failed to decode join room request data")
		s.sendJoinRoomErrorResponse(msg.Rid, 1, "failed to decode request data", connId,
			reqData.RoomId, reqData.UserId)
		return nil
	}

	if err := s.checkJoinRoomReqData(reqData); err != nil {
		LOG(msg.Rid).WithError(err).Error("Join room request data validation failed")
		s.sendJoinRoomErrorResponse(msg.Rid, 1, err.Error(), connId,
			reqData.RoomId, reqData.UserId)
		return nil
	}

	userIds := []string{}
	for _, user := range s.roomMgr.GetUserList(reqData.RoomId) {
		userIds = append(userIds, user.UserId)
	}

	if err := s.roomMgr.AddUserToRoom(msg.Rid, reqData.RoomId, RoomUser{
		UserId:    reqData.UserId,
		ConnId:    connId,
		RtpCaps:   *reqData.RtpCaps,
		Producers: make(map[string]*Producer),
		Consumers: make(map[string]*Consumer),
	}); err != nil {
		LOG(msg.Rid).WithError(err).Error("Failed to add user to room")
		return err
	}

	s.sendJoinRoomSuccessResponse(msg.Rid, connId, reqData.RoomId, reqData.UserId, userIds)

	return nil
}
